﻿using System;
using SimpleServiceBus.Endpoint;
using SimpleServiceBus.Messages.Management.Monitoring;
using SimpleServiceBus.Persistence.Domain.Management.Repositories;

namespace SimpleServiceBus.EndpointManagement.Server
{
    public class EndpointStatusPersistenceService : EndpointServiceBase, IEndpointStatusPersistenceService
    {
        public event EventHandler<EndpointStatusEventArgs> EndpointStatusPersisted;

        private IEndpointMonitorServerService _monitor;
        private IEndpointStatusAggregationService _aggregator;

        protected override void StartService()
        {
            _monitor = ServiceManager.GetService<IEndpointMonitorServerService>();
            if (_monitor != null)
                AttachToMonitor();

            _aggregator = ServiceManager.GetService<IEndpointStatusAggregationService>();
            if (_aggregator != null)
                AttachToAggregator();
        }

        protected override void ShutDownService()
        {
            if (_monitor != null)
            {
                DetachFromMonitor();
                _monitor = null;
            }
            if (_aggregator != null)
            {
                DetachFromAggregator();
                _aggregator = null;
            }
        }

        private void AttachToMonitor()
        {
            _monitor.EndpointStatusUpdated += _monitor_EndpointStatusUpdated;
            _monitor.EndpointStatusExpired += _monitor_EndpointStatusExpired;
        }

        private void DetachFromMonitor()
        {
            _monitor.EndpointStatusUpdated -= _monitor_EndpointStatusUpdated;
            _monitor.EndpointStatusExpired -= _monitor_EndpointStatusExpired;
        }
       
        private void AttachToAggregator()
        {
            _aggregator.EndpointStatusSummaryUpdated += _aggregator_EndpointStatusSummaryUpdated;
        }

        private void DetachFromAggregator()
        {
            _aggregator.EndpointStatusSummaryUpdated -= _aggregator_EndpointStatusSummaryUpdated;
        }

        void _monitor_EndpointStatusExpired(object sender, EndpointStatusEventArgs e)
        {
            PersistStatus(e.LastStatusMessage);
        }

        void _monitor_EndpointStatusUpdated(object sender, EndpointStatusEventArgs e)
        {
            PersistStatus(e.LastStatusMessage);
        }

        void _aggregator_EndpointStatusSummaryUpdated(object sender, EndpointStatusSummaryEventArgs e)
        {
            PersistPerformanceSummaries(e.StatusSummary);
        }

        protected virtual void PersistPerformanceSummaries(EndpointStatusSummaryNotification summaries)
        {
            var repository = ServiceManager.GetService<IEndpointStatusRepository>();

            if (repository == null)
                return;

            repository.UpdateStatusSummaries(summaries);
        }

        protected virtual void PersistStatus(EndpointStatusMessage summary)
        {
            var repository = ServiceManager.GetService<IEndpointStatusRepository>();

            //A null repository means the end user of this endpoint did not provider one
            //A default repository is not automatically registered because 
            //a persistence layer requires far too much configuration to make assumptions about.
            if (repository == null)
                return;

            if (summary is EndpointStatusUpdateNotification)
                repository.AddEndpointStatus((EndpointStatusUpdateNotification) summary);
            if (summary is EndpointOnlineNotification)
                repository.UpdateEndpointOnlineStatus((EndpointOnlineNotification) summary);
            if (summary is EndpointOfflineNotification)
                repository.UpdateEndpointOfflineStatus((EndpointOfflineNotification) summary);
            if (summary is EndpointStatusExpiredNotification)
                repository.UpdateEndpointExpiredStatus((EndpointStatusExpiredNotification) summary);
            if (summary is EndpointErrorNotification)
                repository.AddEndpointError((EndpointErrorNotification) summary);


        }
    }
}